package com.alfayun.fiscalriskanalysis.util;

import java.time.Clock;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;

public final class DateTimeUtils {

	private static Inner instance = new Inner();

	public static Instant instantNow() {
		return instance.instantNow();
	}

	public static LocalDate localDateNow() {
		return instance.localDateNow();
	}

	public static LocalDateTime localDateTimeNow() {
		return instance.localDateTimeNow();
	}

	public static YearMonth yearMonthNow() {
		return instance.yearMonthNow();
	}

	public static void useFixedClockAt(long timestamp) {
		instance.useFixedClockAt(timestamp);
	}

	public static void useFixedClockAt(LocalDateTime time) {
		instance.useFixedClockAt(time);
	}

	public static void useSystemDefaultZoneClock() {
		instance.useSystemDefaultZoneClock();
	}

	public static Inner newInner() {
		return new Inner();
	}

	private DateTimeUtils() {
		// Empty.
	}

	public static class Inner {
		private Clock clock = Clock.systemDefaultZone();

		public Instant instantNow() {
			return Instant.now(clock);
		}

		public LocalDate localDateNow() {
			return LocalDate.now(clock);
		}

		public LocalDateTime localDateTimeNow() {
			return LocalDateTime.now(clock);
		}

		public YearMonth yearMonthNow() {
			return YearMonth.now(clock);
		}

		public void useFixedClockAt(long timestamp) {
			clock = Clock.fixed(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
		}

		public void useFixedClockAt(LocalDateTime time) {
			clock = Clock.fixed(time.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault());
		}

		public void useFixedClockAt(LocalDateTime time, ZoneId zone) {
			clock = Clock.fixed(time.atZone(zone).toInstant(), zone);
		}

		public void useSystemDefaultZoneClock() {
			clock = Clock.systemDefaultZone();
		}

		private Inner() {
			// Empty.
		}
	}
}
